package com.whmskj.xjlhsc.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.whmskj.xjlhsc.controller.fo.TaskStatisticsFo;
import com.whmskj.xjlhsc.entity.SpecialUseRecord;
import com.whmskj.xjlhsc.entity.WbPlan;
import com.whmskj.xjlhsc.enums.ScEnums.ITEM_TYPE;
import com.whmskj.xjlhsc.exception.BusinessException;
import com.whmskj.xjlhsc.exception.ExceptionText;
import com.whmskj.xjlhsc.jitapi.dto.Emp;
import com.whmskj.xjlhsc.jitapi.entity.Device;
import com.whmskj.xjlhsc.jitapi.entity.InventoryRecord;
import com.whmskj.xjlhsc.jitapi.mapper.*;
import com.whmskj.xjlhsc.mapper.SpecialUseRecordMapper;
import com.whmskj.xjlhsc.mapper.WbRecordMapper;
import com.whmskj.xjlhsc.entity.WbRecord;
import com.whmskj.xjlhsc.mobie.equipment.controller.fo.ApproveListFo;
import com.whmskj.xjlhsc.mobie.equipment.controller.fo.RepairTaskListFo;
import com.whmskj.xjlhsc.mobie.equipment.dto.ApproveDto;
import com.whmskj.xjlhsc.schedul.delayTask.DelayTask;
import com.whmskj.xjlhsc.schedul.delayTask.DelayTaskScheduler;
import com.whmskj.xjlhsc.service.SpecialUseRecordService;
import com.whmskj.xjlhsc.service.WbPlanService;
import com.whmskj.xjlhsc.service.WbRecordService;
import com.whmskj.xjlhsc.service.dto.DeviceNoVo;
import com.whmskj.xjlhsc.service.dto.RepairTaskDto;
import com.whmskj.xjlhsc.service.dto.TaskStatisticsDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.whmskj.xjlhsc.enums.ScEnums.*;
import static com.whmskj.xjlhsc.enums.ScEnums.ITEM_TYPE.DEVICE;
import static com.whmskj.xjlhsc.enums.ScEnums.ITEM_TYPE.PROJECT;

/**
 * @author lk
 * @since 2025-06-16 13:31:13
 */
@Service
@Slf4j
public class WbRecordServiceImpl extends ServiceImpl<WbRecordMapper, WbRecord> implements WbRecordService {

    @Autowired
    private WbRecordMapper wbRecordMapper;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private InventoryMapper inventoryMapper;
    @Autowired
    private WbPlanService wbPlanService;
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private DictMapper dictMapper;
    @Autowired
    private SpecialUseRecordService specialUseRecordService;
    @Autowired
    private ClassGroupMapper classGroupMapper;
    @Autowired
    private SpecialUseRecordMapper specialUseRecordMapper;

    @Override
    public Page<WbRecord> findPage(WbRecord params) {
        Page<WbRecord> page = new Page<>(1, 10);//TODO 自行处理
        LambdaQueryWrapper<WbRecord> query = Wrappers.lambdaQuery(WbRecord.class);
        query.isNotNull(WbRecord::getWbRecordState);
        query.eq(ObjectUtil.isNotNull(params.getWbRecordState()), WbRecord::getWbRecordState, params.getWbRecordState());

        if (CollectionUtil.isNotEmpty(params.getDateRange())) {
            query.ge(WbRecord::getPlanDate, params.getDateRange().get(0));
            query.le(WbRecord::getPlanDate, params.getDateRange().get(1));
        }
        Page<WbRecord> wbRecordPage = wbRecordMapper.selectPage(page, query);
        List<WbRecord> records = wbRecordPage.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            Map<Integer, Device> deviceMap = deviceMapper.selectByIds(records.stream().map(WbRecord::getDeviceId).collect(Collectors.toSet())).stream().collect(Collectors.toMap(Device::getDeviceId, Function.identity()));

            LambdaQueryWrapper<WbPlan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(WbPlan::getMaintenancePlanId, records.stream().map(WbRecord::getPlanId).collect(Collectors.toSet()));

            Map<Long, WbPlan> planMap = wbPlanService.list(queryWrapper).stream().collect(Collectors.toMap(WbPlan::getMaintenancePlanId, Function.identity()));

            for (WbRecord record : records) {
                Device device = deviceMap.get(record.getDeviceId());
                record.setDeviceName(device.getDeviceName());
                record.setProcessName(device.getProcess());
                record.setDeviceNo(device.getDeviceNo());
                record.setWorkshop(device.getWorkShop());

                WbPlan wbPlan = planMap.get(record.getPlanId());
                record.setType(wbPlan.getType());
                record.setItemType(wbPlan.getItemType());
            }
        }
        return wbRecordPage;
    }

    @Override
    public List<WbRecord> findList(WbRecord params) {
        LambdaQueryWrapper<WbRecord> query = Wrappers.lambdaQuery(WbRecord.class);
        return wbRecordMapper.selectList(query);
    }

    @Override
    public WbRecord findById(Long id) {
        WbRecord wbRecord = wbRecordMapper.selectById(id);
        List<SpecialUseRecord> specialUseRecords = specialUseRecordService.list(Wrappers.lambdaQuery(SpecialUseRecord.class).eq(SpecialUseRecord::getWbRecordId, wbRecord.getRecordId()));
        wbRecord.setSpecialUseRecordList(specialUseRecords);
        //维保任务对应机台
        Device device = deviceMapper.getById(wbRecord.getDeviceId());
        StringJoiner sj = new StringJoiner("/");
        sj.add(device.getProcess());
        sj.add(device.getDeviceName());
        sj.add(device.getDeviceNo());
        wbRecord.setDeviceName(sj.toString());
        wbRecord.setDeviceNo(device.getDeviceNo());

        WbPlan wbPlan = wbPlanService.getById(wbRecord.getPlanId());
        wbRecord.setType(wbPlan.getType());
        wbRecord.setItemType(wbPlan.getItemType());
        if (ObjectUtil.isNotNull(wbRecord.getPlanDate()) && ObjectUtil.isNotNull(wbRecord.getEndTime())) {
            //计算花费时间多少份多少秒
            long second = DateUtil.between(wbRecord.getPlanDate(), wbRecord.getEndTime(), DateUnit.SECOND);
            wbRecord.setUseTime(convertSeconds(second));
        }
        return wbRecord;
    }

    private String convertSeconds(long totalSeconds) {
        long minutes = totalSeconds / 60;
        long seconds = totalSeconds % 60;
        return String.format("%02d分%02d秒", minutes, seconds);
    }

    @Override
    public boolean insert(WbRecord wbRecord) {

//        Executors.newSingleThreadExecutor().submit(()->{
//            wbRecord.get
//
//
//            DelayTaskScheduler instance = DelayTaskScheduler.getInstance();
//            instance.addTask(new DelayTask(wbRecord.getRecordId(),));
//        })

        return save(wbRecord);
    }

    @Override
    public boolean update(WbRecord wbRecord) {
        return updateById(wbRecord);
    }

    @Override
    public int delete(Long id) {
        return wbRecordMapper.deleteById(id);
    }


    @Override
    public TaskStatisticsDto taskStatistics(TaskStatisticsFo fo) {
        List<String> tableHeadList = getMonthOfDayList(fo);
        List<Map<String, Object>> tableDataList = new ArrayList<>();
        TaskStatisticsDto taskStatisticsDto = new TaskStatisticsDto();
        taskStatisticsDto.setTableDataList(tableDataList);


        String substring = fo.getYm().substring(0, 5);
        List<String> days = tableHeadList.stream().map(item -> substring + item.substring(0, 5)).toList();
        fo.setDays(days);
        List<WbRecord> wbRecords = baseMapper.listByTaskStatistics(fo);

        if (ITEM_TYPE.PROJECT.getCode().equals(fo.getType())) {
            tableHeadList.add(0, ITEM_TYPE.PROJECT.getDescription());
        } else if (DEVICE.getCode().equals(fo.getType())) {
            tableHeadList.add(0, DEVICE.getDescription());
        }

        taskStatisticsDto.setTableHeadList(tableHeadList.stream().map(cur -> {
            Map<String, Object> map = new LinkedHashMap<>(1);
            map.put("columnName", cur);
            return map;
        }).toList());


        if (CollectionUtil.isEmpty(wbRecords)) return taskStatisticsDto;


        Map<Long, WbPlan> planMap = wbPlanService.listByIds(wbRecords.stream().map(WbRecord::getPlanId).collect(Collectors.toSet())).stream().collect(Collectors.toMap(WbPlan::getMaintenancePlanId, Function.identity()));

        Map<Integer, List<WbRecord>> groups;
        if (DEVICE.getCode().equals(fo.getType()))
            groups = wbRecords.stream().collect(Collectors.groupingBy(WbRecord::getDeviceId));
        else groups = wbRecords.stream().collect(Collectors.groupingBy(WbRecord::getItemType));


        Map<Integer, String> deviceIdMapNo = deviceMapper.allDevice().stream().collect(Collectors.toMap(Device::getDeviceId, Device::getDeviceNo));

        for (Map.Entry<Integer, List<WbRecord>> entry : groups.entrySet()) {
            Integer id = entry.getKey();
            String desc = "";
            if (ITEM_TYPE.PROJECT.getCode().equals(fo.getType())) desc = SCWBXM.getDescriptionByCode(id);
            else desc = deviceIdMapNo.get(id);
            LinkedHashMap<String, Object> row = new LinkedHashMap<>();
            row.put(tableHeadList.get(0), desc);

            List<WbRecord> records = entry.getValue();
            for (int i = 1; i < tableHeadList.size(); i++) {
                String date = fo.getYm().substring(0, 5) + tableHeadList.get(i).substring(0, 5);
                List<WbRecord> list = records.stream().filter(item -> DateUtil.formatDate(item.getPlanDate()).equals(date)).toList();

                if (CollectionUtil.isEmpty(list)) {
                    row.put(tableHeadList.get(i), CollectionUtil.empty(List.class));
                    continue;
                }
                List<DeviceNoVo> voList = list.stream().map(cur -> {
                    DeviceNoVo deviceNoVo = new DeviceNoVo();
                    deviceNoVo.setDeviceId(cur.getDeviceId());
                    deviceNoVo.setDeviceNo(deviceIdMapNo.get(cur.getDeviceId()));
                    deviceNoVo.setWbTjState(cur.getWbTjState());
                    if (DEVICE.getCode().equals(fo.getType())) {
                        WbPlan wbPlan = planMap.get(cur.getPlanId());
                        deviceNoVo.setItemType(SCWBXM.getDescriptionByCode(wbPlan.getItemType()));
                    }

                    return deviceNoVo;
                }).toList();

                row.put(tableHeadList.get(i), voList);
            }
            tableDataList.add(row);
        }

        //如果没有查询到这个项目类型也要展示
        if (PROJECT.getCode().equals(fo.getType())) {
            List<HashMap<String, Boolean>> typeMap = Arrays.stream(SCWBXM.values()).map(cur -> MapUtil.of(cur.getDescription(), Boolean.FALSE)).toList();
            List<String> types = Arrays.stream(SCWBXM.values()).map(SCWBXM::getDescription).toList();

            for (String type : types) {
                boolean flag = true;
                for (Map<String, Object> data : tableDataList) {
                    if (type.equals(data.get(PROJECT.getDescription()))) {
                        flag = false;
                        break;
                    }
                }
                final boolean flag1 = flag;
                typeMap.stream().filter(cur -> cur.containsKey(type)).forEach(cur -> cur.put(type, flag1));
            }
            for (HashMap<String, Boolean> map : typeMap) {
                Set<String> strings = map.keySet();
                for (String key : strings) {
                    if (map.get(key)) {
                        LinkedHashMap<String, Object> data = new LinkedHashMap<>();
                        data.put(PROJECT.getDescription(), key);
                        tableDataList.add(data);
                    }
                }
            }


        } else {
            //列出工序的所有机台
            List<Device> devices = deviceMapper.getDeviceListByProcess(fo.getProcess());
            for (Device device : devices) {
                boolean flag = true;
                for (Map<String, Object> data : tableDataList) {
                    String deviceNo = data.get(DEVICE.getDescription()).toString();
                    if (deviceNo.equals(device.getDeviceNo())) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    LinkedHashMap<String, Object> data = new LinkedHashMap<>();
                    data.put(DEVICE.getDescription(), device.getDeviceNo());
                    tableDataList.add(data);
                }
            }
        }

        tableDataList.sort(Comparator.comparing(data -> {
            String key = DEVICE.getCode().equals(fo.getType()) ? DEVICE.getDescription() : PROJECT.getDescription();
            return data.get(key).toString();
        }));
        return taskStatisticsDto;
    }

    private List<String> getMonthOfDayList(TaskStatisticsFo fo) {
        List<String> dateList = new ArrayList<>();


        if (MONTH_TYPE.ZRY.getCode().equals(fo.getMonthType())) {
            YearMonth yearMonth = YearMonth.parse(fo.getYm());


            LocalDate startDate = yearMonth.atDay(1);
            LocalDate endDate = yearMonth.atEndOfMonth();


            for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
                String chineseWeek = date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINA);
                dateList.add(date.format(formatter) + chineseWeek);

            }
        } else {
            //查询盘存月
            List<InventoryRecord> inventoryRecordList = inventoryMapper.getInventoryRecordByYm(fo.getYm());
            inventoryRecordList.forEach(item -> {
                String date = item.getDate();
                LocalDate parse = LocalDate.parse(date);
                String chineseWeek = parse.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINA);
                dateList.add(date.substring(5) + chineseWeek);
            });
        }
        return dateList;
    }


    @Override
    public List<RepairTaskDto> getRepairTaskList(RepairTaskListFo fo) {
        if ("全部".equals(fo.getProcess()))
            fo.setProcess(null);
        String userId = StpUtil.getLoginId().toString();
        log.info("当前极态登录用户ID：{}", userId);
        //user定位员工ID
        Emp emp = Optional.ofNullable(empMapper.selectEmpByUserId(userId)).orElseGet(Emp::new);
        log.info("当前极态登录员工信息：{}", JSONUtil.toJsonStr(emp));
        fo.setEmpId(emp.getEmpId());
        return wbRecordMapper.getRepairTaskList(fo);
    }


    @Override
    public WbRecord scanToProcess(Long recordId, Integer deviceId) {
        List<WbRecord> list = list(Wrappers.lambdaQuery(WbRecord.class).eq(WbRecord::getRecordId, recordId).eq(WbRecord::getDeviceId, deviceId));
        if (CollectionUtil.isEmpty(list)) throw new BusinessException(ExceptionText.SCAN_CORRECT_DEVICE);
        WbRecord task = list.get(0);
        //维保任务对应机台
        Device device = deviceMapper.getById(deviceId);
        StringJoiner sj = new StringJoiner("/");
        sj.add(device.getProcess());
        sj.add(device.getDeviceName());
        sj.add(device.getDeviceNo());
        task.setDeviceName(sj.toString());
        task.setStartTime(new Date());
        return task;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean taskSubmit(WbRecord wbRecord) {
        if (wbRecord.getWbJdState().equals(SCWBJDZT.UNPROCESSED.getCode()) || wbRecord.getWbJdState().equals(SCWBJDZT.OVERD.getCode())) {
            wbRecord.setStartTime(new Date());
        }
        //变更状态
        wbRecord.setWbRecordState(SCWBJLZT.PENDING_REVIEW.getCode());
        wbRecord.setWbJdState(SCWBJDZT.PROCESSED.getCode());
        wbRecord.setWbTjState(SCWBTJZT.PENDING_REVIEW2.getCode());
        wbRecord.setWbShState(SCWBSHZT.UNAPP.getCode());
        wbRecord.setEndTime(new Date());
        wbRecord.setOverdueDay(DateUtil.betweenDay(wbRecord.getPlanDate(), new Date(), true) + "");

        LambdaQueryWrapper<SpecialUseRecord> delWrapper = Wrappers.lambdaQuery();
        delWrapper.eq(SpecialUseRecord::getWbRecordId, wbRecord.getRecordId());
        List<SpecialUseRecord> beforeSpecialUseRecords = specialUseRecordMapper.selectList(delWrapper);
        LocalDateTime addTime=null;
        if (CollectionUtil.isNotEmpty(beforeSpecialUseRecords)) {
            addTime = beforeSpecialUseRecords.get(0).getAddTime();
        }

        List<SpecialUseRecord> specialUseRecordList = wbRecord.getSpecialUseRecordList();

        for (SpecialUseRecord cur : specialUseRecordList) {
            if (cur.getAddTime()==null || addTime==null){
                cur.setAddTime(LocalDateTime.now());
            }else {
                cur.setAddTime(addTime);
            }
            cur.setWbRecordId(wbRecord.getRecordId());
            cur.setSpecialType(wbRecord.getSpecialType());
        }
        specialUseRecordService.remove(delWrapper);

        specialUseRecordService.saveBatch(specialUseRecordList);


//        specialUseRecordService.remove(delWrapper);
//        List<SpecialUseRecord> specialUseRecordList = wbRecord.getSpecialUseRecordList();
//        specialUseRecordList.forEach(cur -> {
//            cur.setWbRecordId(wbRecord.getRecordId());
//            cur.setSpecialType(wbRecord.getSpecialType());
//        });
//        specialUseRecordService.saveBatch(specialUseRecordList);

        return update(wbRecord);
    }

    @Override
    public List<ApproveDto> getApproveList(ApproveListFo fo) {
        String userId = StpUtil.getLoginId().toString();
        //user定位员工
        Emp emp = Optional.ofNullable(empMapper.selectEmpByUserId(userId)).orElseGet(Emp::new);
        //通过员工姓名查看能审核哪些维保人
//        String className = classGroupMapper.findClassNameByPrincipalName(emp.getEmpName());
        List<Emp> empList = empMapper.empListByEmpName(emp.getEmpName());

        List<Integer> empIds = empList.stream().map(Emp::getEmpId).toList();

        if (CollectionUtil.isEmpty(empList)) return CollectionUtil.empty(List.class);

        fo.setEmpIds(empIds);

        return wbRecordMapper.getApproveList(fo);
    }


    @Override
    public WbRecord getApproveDetail(Long recordId) {
        WbRecord wbRecord = getById(recordId);
        Device device = deviceMapper.getById(wbRecord.getDeviceId());
        wbRecord.setDeviceNo(device.getDeviceNo());
        StringJoiner sj = new StringJoiner("/");
        sj.add(device.getProcess());
        sj.add(device.getDeviceName());
        sj.add(device.getDeviceNo());
        wbRecord.setDeviceName(sj.toString());
        return wbRecord;
    }

    /**
     * 维保任务临时提交
     * @param wbRecord
     * @return
     */
    @Override
    public boolean taskSubmitTemp(WbRecord wbRecord) {
        LambdaQueryWrapper<SpecialUseRecord> delWrapper = Wrappers.lambdaQuery();
        delWrapper.eq(SpecialUseRecord::getWbRecordId, wbRecord.getRecordId());
        List<SpecialUseRecord> beforeSpecialUseRecords = specialUseRecordMapper.selectList(delWrapper);
        LocalDateTime addTime=null;
        if (CollectionUtil.isNotEmpty(beforeSpecialUseRecords)) {
            addTime = beforeSpecialUseRecords.get(0).getAddTime();
        }

        List<SpecialUseRecord> specialUseRecordList = wbRecord.getSpecialUseRecordList();

        for (SpecialUseRecord cur : specialUseRecordList) {
            if (cur.getAddTime()==null || addTime==null){
                cur.setAddTime(LocalDateTime.now());
            }else {
                cur.setAddTime(addTime);
            }
            cur.setWbRecordId(wbRecord.getRecordId());
            cur.setSpecialType(wbRecord.getSpecialType());
        }
        specialUseRecordService.remove(delWrapper);

        specialUseRecordService.saveBatch(specialUseRecordList);

        return update(wbRecord);
    }
}